package com.yanfan.ba.modbus.test;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class ModbusSender {

    /**
     * 发送自定义的 Modbus 指令，并返回响应数据
     *
     * @param ip Modbus 服务器 IP 地址
     * @param port Modbus TCP 端口
     * @param command 发送的 Modbus 指令
     * @return 返回从服务器接收的响应数据
     * @throws Exception 出现连接或读取错误时抛出异常
     */
    public static byte[] sendCustomModbusCommand(String ip, int port, byte[] command) throws Exception {
        // 初始化响应数据数组
        byte[] response = new byte[256];  // 假设最大响应数据不超过 256 字节

        try (Socket socket = new Socket(ip, port);
             OutputStream out = socket.getOutputStream();
             InputStream in = socket.getInputStream()) {

            // 发送 Modbus 报文
            out.write(command);
            out.flush();
            System.out.println("已发送 Modbus 指令至服务器。");

            // 读取响应数据
            int length = in.read(response);  // 读取实际的响应长度

            if (length == -1) {
                throw new Exception("未收到服务器响应，连接可能已关闭。");
            }

            // 截取有效的响应数据
            byte[] trimmedResponse = new byte[length];
            System.arraycopy(response, 0, trimmedResponse, 0, length);

            return trimmedResponse;

        } catch (Exception e) {
            System.err.println("与 Modbus 服务器通信失败：" + e.getMessage());
            throw e;  // 抛出异常以便在调用处处理
        }
    }

    /**
     * 解析 Modbus 响应并判断指令是否成功
     *
     * @param response Modbus 响应数据
     * @return 成功返回 true，失败返回 false
     */
    public static boolean isModbusCommandSuccessful(byte[] response) {
        // 响应数据至少应有 5 个字节：事务标识符、协议标识符、长度、设备地址和功能码
        if (response.length < 5) {
            return false; // 响应数据格式错误
        }

        // 检查功能码
        byte functionCode = response[1];
        // 如果功能码与请求的功能码相同，则表示成功
        if (functionCode == response[7]) {
            return true; // 成功
        }

        // 如果功能码高位有 0x80 则表示出错
        if ((functionCode & 0x80) != 0) {
            return false; // 失败
        }

        return false; // 默认返回失败
    }

    public static void main(String[] args) {
        String ip = "192.168.23.201"; // Modbus 服务器 IP
        int port = 502; // Modbus TCP 端口

        // 构造 Modbus 报文
        byte[] command = new byte[]{
                0x12, 0x54, 0x00, 0x00, 0x00, 0x06, 0x01, 0x06,
                (byte) 0x9C, (byte) 0x40, 0x00, 0x01,
        };

        try {
            // 发送 Modbus 指令并接收响应
            byte[] response = sendCustomModbusCommand(ip, port, command);
            System.out.println("已接收到服务器的响应数据：");

            // 打印响应数据（十六进制格式）
            for (byte b : response) {
                System.out.printf("0x%02X ", b);
            }
            System.out.println();

            // 检查指令是否成功
            if (isModbusCommandSuccessful(response)) {
                System.out.println("指令发送成功。");
            } else {
                System.out.println("指令发送失败。");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
